function _iframeDoc(iframe) {
  iframe = _get(iframe);
  return iframe.contentDocument || iframe.contentWindow.document;
}

var html,
  _direction = "";
if ((html = document.getElementsByTagName("html"))) {
  _direction = html[0].dir;
}

function _getInitHtml(themesPath, bodyClass, cssPath, cssData) {
  var arr = [
    _direction === "" ? "<html>" : '<html dir="' + _direction + '">',
    '<head><meta charset="utf-8" /><title></title>',
    "<style>",
    "html {margin:0;padding:0;}",
    "body {margin:0;padding:5px;}",
    'body, td {font:12px/1.5 "sans serif",tahoma,verdana,helvetica;}',
    "body, p, div {word-wrap: break-word;}",
    "p {margin:5px 0;}",
    "table {border-collapse:collapse;}",
    "img {border:0;}",
    "noscript {display:none;}",
    "table.ke-zeroborder td {border:1px dotted #AAA;}",
    "img.ke-flash {",
    "	border:1px solid #AAA;",
    "	background-image:url(" + themesPath + "common/flash.gif);",
    "	background-position:center center;",
    "	background-repeat:no-repeat;",
    "	width:100px;",
    "	height:100px;",
    "}",
    "img.ke-rm {",
    "	border:1px solid #AAA;",
    "	background-image:url(" + themesPath + "common/rm.gif);",
    "	background-position:center center;",
    "	background-repeat:no-repeat;",
    "	width:100px;",
    "	height:100px;",
    "}",
    "img.ke-media {",
    "	border:1px solid #AAA;",
    "	background-image:url(" + themesPath + "common/media.gif);",
    "	background-position:center center;",
    "	background-repeat:no-repeat;",
    "	width:100px;",
    "	height:100px;",
    "}",
    "img.ke-anchor {",
    "	border:1px dashed #666;",
    "	width:16px;",
    "	height:16px;",
    "}",
    ".ke-script, .ke-noscript, .ke-display-none {",
    "	display:none;",
    "	font-size:0;",
    "	width:0;",
    "	height:0;",
    "}",
    ".ke-pagebreak {",
    "	border:1px dotted #AAA;",
    "	font-size:0;",
    "	height:2px;",
    "}",
    "</style>"
  ];
  if (!_isArray(cssPath)) {
    cssPath = [cssPath];
  }
  _each(cssPath, function(i, path) {
    if (path) {
      arr.push('<link href="' + path + '" rel="stylesheet" />');
    }
  });
  if (cssData) {
    arr.push("<style>" + cssData + "</style>");
  }
  arr.push(
    "</head><body " +
      (bodyClass ? 'class="' + bodyClass + '"' : "") +
      "></body></html>"
  );
  return arr.join("\n");
}

function _elementVal(knode, val) {
  if (knode.hasVal()) {
    if (val === undefined) {
      var html = knode.val();
      // 去除内容为空的p标签
      // https://github.com/kindsoft/kindeditor/pull/52
      html = html.replace(/(<(?:p|p\s[^>]*)>) *(<\/p>)/gi, "");
      return html;
    }
    return knode.val(val);
  }
  return knode.html(val);
}

// create KEdit class
function KEdit(options) {
  this.init(options);
}
_extend(KEdit, KWidget, {
  init: function(options) {
    var self = this;
    KEdit.parent.init.call(self, options);

    self.srcElement = K(options.srcElement);
    self.div.addClass("ke-edit");
    self.designMode = _undef(options.designMode, true);
    self.beforeGetHtml = options.beforeGetHtml;
    self.beforeSetHtml = options.beforeSetHtml;
    self.afterSetHtml = options.afterSetHtml;

    var themesPath = _undef(options.themesPath, ""),
      bodyClass = options.bodyClass,
      cssPath = options.cssPath,
      cssData = options.cssData,
      isDocumentDomain =
        location.protocol != "res:" &&
        location.host.replace(/:\d+/, "") !== document.domain,
      srcScript =
        "document.open();" +
        (isDocumentDomain ? 'document.domain="' + document.domain + '";' : "") +
        "document.close();",
      iframeSrc = _IE
        ? ' src="javascript:void(function(){' +
          encodeURIComponent(srcScript) +
          '}())"'
        : "";
    self.iframe = K(
      '<iframe class="ke-edit-iframe" hidefocus="true" frameborder="0"' +
        iframeSrc +
        "></iframe>"
    ).css("width", "100%");
    self.textarea = K(
      '<textarea class="ke-edit-textarea" hidefocus="true"></textarea>'
    ).css("width", "100%");
    self.tabIndex = isNaN(parseInt(options.tabIndex, 10))
      ? self.srcElement.attr("tabindex")
      : parseInt(options.tabIndex, 10);
    self.iframe.attr("tabindex", self.tabIndex);
    self.textarea.attr("tabindex", self.tabIndex);

    if (self.width) {
      self.setWidth(self.width);
    }
    if (self.height) {
      self.setHeight(self.height);
    }
    if (self.designMode) {
      self.textarea.hide();
    } else {
      self.iframe.hide();
    }
    function ready() {
      var doc = _iframeDoc(self.iframe);
      doc.open();
      if (isDocumentDomain) {
        doc.domain = document.domain;
      }
      doc.write(_getInitHtml(themesPath, bodyClass, cssPath, cssData));
      doc.close();
      self.win = self.iframe[0].contentWindow;
      self.doc = doc;
      var cmd = _cmd(doc);
      // add events
      self.afterChange(function(e) {
        cmd.selection();
      });
      // [WEBKIT] select an image after click the image
      if (_WEBKIT) {
        K(doc).click(function(e) {
          if (K(e.target).name === "img") {
            cmd.selection(true);
            cmd.range.selectNode(e.target);
            cmd.select();
          }
        });
      }
      if (_IE) {
        // Fix bug: https://github.com/kindsoft/kindeditor/issues/53
        self._mousedownHandler = function() {
          var newRange = cmd.range.cloneRange();
          newRange.shrink();
          if (newRange.isControl()) {
            self.blur();
          }
        };
        K(document).mousedown(self._mousedownHandler);
        // [IE] bug: clear iframe when press backspase key
        K(doc).keydown(function(e) {
          if (e.which == 8) {
            cmd.selection();
            var rng = cmd.range;
            if (rng.isControl()) {
              rng.collapse(true);
              K(rng.startContainer.childNodes[rng.startOffset]).remove();
              e.preventDefault();
            }
          }
        });
      }
      self.cmd = cmd;
      self.html(_elementVal(self.srcElement));
      if (_IE) {
        doc.body.disabled = true;
        doc.body.contentEditable = true;
        doc.body.removeAttribute("disabled");
      } else {
        doc.designMode = "on";
      }
      if (options.afterCreate) {
        options.afterCreate.call(self);
      }
    }
    if (isDocumentDomain) {
      self.iframe.bind("load", function(e) {
        self.iframe.unbind("load");
        if (_IE) {
          ready();
        } else {
          setTimeout(ready, 0);
        }
      });
    }
    self.div.append(self.iframe);
    self.div.append(self.textarea);
    self.srcElement.hide();
    !isDocumentDomain && ready();
  },
  setWidth: function(val) {
    var self = this;
    val = _addUnit(val);
    self.width = val;
    self.div.css("width", val);
    return self;
  },
  setHeight: function(val) {
    var self = this;
    val = _addUnit(val);
    self.height = val;
    self.div.css("height", val);
    self.iframe.css("height", val);
    // 校正IE6和IE7的textarea高度
    if ((_IE && _V < 8) || _QUIRKS) {
      val = _addUnit(_removeUnit(val) - 2);
    }
    self.textarea.css("height", val);
    return self;
  },
  remove: function() {
    var self = this,
      doc = self.doc;
    // remove events
    K(doc.body).unbind();
    K(doc).unbind();
    K(self.win).unbind();
    if (self._mousedownHandler) {
      K(document).unbind("mousedown", self._mousedownHandler);
    }
    // remove elements
    _elementVal(self.srcElement, self.html());
    self.srcElement.show();
    // doc.write('');
    self.iframe.unbind();
    self.textarea.unbind();
    KEdit.parent.remove.call(self);
  },
  html: function(val, isFull) {
    var self = this,
      doc = self.doc;
    // design mode
    if (self.designMode) {
      var body = doc.body;
      // get
      if (val === undefined) {
        if (isFull) {
          val = "<!doctype html><html>" + body.parentNode.innerHTML + "</html>";
        } else {
          val = body.innerHTML;
        }
        if (self.beforeGetHtml) {
          val = self.beforeGetHtml(val);
        }
        // bugfix: Firefox自动生成一个br标签
        if (_GECKO && val == "<br />") {
          val = "";
        }
        return val;
      }
      // set
      if (self.beforeSetHtml) {
        val = self.beforeSetHtml(val);
      }
      // IE9 Bugfix: https://github.com/kindsoft/kindeditor/issues/62
      if (_IE && _V >= 9) {
        val = val.replace(/(<.*?checked=")checked(".*>)/gi, "$1$2");
      }
      K(body).html(val);
      if (self.afterSetHtml) {
        self.afterSetHtml();
      }
      return self;
    }
    // source mode
    if (val === undefined) {
      return self.textarea.val();
    }
    self.textarea.val(val);
    return self;
  },
  design: function(bool) {
    var self = this,
      val;
    if (bool === undefined ? !self.designMode : bool) {
      if (!self.designMode) {
        val = self.html();
        self.designMode = true;
        self.html(val);
        self.textarea.hide();
        self.iframe.show();
      }
    } else {
      if (self.designMode) {
        val = self.html();
        self.designMode = false;
        self.html(val);
        self.iframe.hide();
        self.textarea.show();
      }
    }
    return self.focus();
  },
  focus: function() {
    var self = this;
    self.designMode ? self.win.focus() : self.textarea[0].focus();
    return self;
  },
  blur: function() {
    var self = this;
    if (_IE) {
      var input = K(
        '<input type="text" style="float:left;width:0;height:0;padding:0;margin:0;border:0;" value="" />',
        self.div
      );
      self.div.append(input);
      input[0].focus();
      input.remove();
    } else {
      self.designMode ? self.win.blur() : self.textarea[0].blur();
    }
    return self;
  },
  afterChange: function(fn) {
    var self = this,
      doc = self.doc,
      body = doc.body;
    K(doc).keyup(function(e) {
      if (!e.ctrlKey && !e.altKey && _CHANGE_KEY_MAP[e.which]) {
        fn(e);
      }
    });
    K(doc)
      .mouseup(fn)
      .contextmenu(fn);
    K(self.win).blur(fn);
    function timeoutHandler(e) {
      setTimeout(function() {
        fn(e);
      }, 1);
    }
    K(body).bind("paste", timeoutHandler);
    K(body).bind("cut", timeoutHandler);
    return self;
  }
});

function _edit(options) {
  return new KEdit(options);
}

K.EditClass = KEdit;
K.edit = _edit;
K.iframeDoc = _iframeDoc;
